/*
 * UserNet  --  TCP/IP implementation in userspace
 * Copyright (C) 2010  Felip Moll
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define DEBUGGING_MSG 0
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <arpa/inet.h>		/* inet_ntoa */
#include "unet/tcp.h"
#include <time.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>

void
unet_tcp_init() {
    /*@Descripció:
       Inicialitza les estructures bàsiques del mòdul TCP.
     */
    pthread_mutex_init(&listen_list_mutex, 0);
    pthread_mutex_init(&connection_list_mutex, 0);
    pthread_mutex_init(&recv_buffer.mutex, 0);
    sem_init(&recv_buffer.sem, 1, -1);

    INIT_LIST_HEAD(&listen_list);
    INIT_LIST_HEAD(&connection_list);

    recv_buffer.left_size = RECV_BUFF_LEN;
    INIT_LIST_HEAD(&(recv_buffer.queue));

    tcp_init = 1;
}

struct unet_tcp_listen_node *
unet_tcp_listen(struct in_addr listen_addr, uint16_t port, int max_pending_syn) {
    TCP_INIT();

    /*@Descripció:
       Aquesta funció es crida quan un servidor executa la crida listen().

       Mantenim una llista enllaçada de elements de tipus listen_list_element.
       Cada element d'aquests representa una crida listen.

       Cada crida listen té una ip, un port, un nombre màxim de peticions de connexió
       (SYN RVCD PACKETS), i finalment una cua amb peticions de connexió en espera.
     */
    struct list_head *position;
    struct unet_tcp_listen_node *current;
    struct unet_tcp_listen_node *new_ln;

    //Bloquejem per si una aplicació modifica la llista de listen
    //mentre l'estem llegint. Per exemple 2 threads, un que fa listen()
    //i un que fa accept() al mateix temps.
    pthread_mutex_lock(&listen_list_mutex);

    list_for_each(position, &listen_list) {

        debug_printf("TCP", "(TCP): Recorrent listen queue: <%s,%u>\n",
                inet_ntoa(listen_addr), port);

        current = list_head_to_listen_node(position);
        if (current->port == htons(port)
                && listen_addr.s_addr == current->listen_addr.s_addr) {
            debug_printf("TCP", "(TCP): Error, there's already a listen() queue for <%s,%u>\n",
                    inet_ntoa(listen_addr), port);
            return NULL;
        }
    }
    pthread_mutex_unlock(&listen_list_mutex);

    new_ln = malloc(sizeof (*new_ln));
    new_ln->port = htons(port);
    new_ln->listen_addr = listen_addr;
    new_ln->pending_syn_slots = max_pending_syn;
    INIT_LIST_HEAD(&(new_ln->syn_rcvd_q));
    pthread_mutex_init(&(new_ln->mutex), 0);
    sem_init(&(new_ln->sem), 1, -1);

    pthread_mutex_lock(&listen_list_mutex);
    list_add(&(new_ln->element), &listen_list);
    pthread_mutex_unlock(&listen_list_mutex);

    debug_printf("TCP", "(TCP): Listening on %s:%u via TCP\n", inet_ntoa(new_ln->listen_addr), ntohs(new_ln->port));

    return new_ln;
}

unet_tcp_connection_t
unet_tcp_connect(struct in_addr dest_addr, uint16_t src_port, uint16_t dst_port) {
    //Ens falta passar l'ip origen per calcular el checksum
    //Active Open
    //Tenim un timeout màx per el thwhandshak.
    //Iniciar un three way h. amb dest_addr, i port i retornar la connexió
    //Quan un client vol obrir una connexió amb un altre host
    //  debug_printf ("connecting with %s:%u via TCP\n", inet_ntoa (dest_addr), port);
    struct unet_tcp_packet * new_packet;
    unet_tcp_connection_t new_tcp_c;
    TCP_INIT();

    //Create a new connection
    new_tcp_c = malloc(sizeof (*new_tcp_c));
    memset(new_tcp_c, 0, sizeof (*new_tcp_c));

    //New connection initialization
    new_tcp_c->remote_addr = dest_addr;
    new_tcp_c->local_port = htons(src_port);
    new_tcp_c->remote_port = htons(dst_port);
    INIT_LIST_HEAD(&(new_tcp_c->packet_queue));
    sem_init(&(new_tcp_c->sem), 1, -1);
    pthread_mutex_init(&(new_tcp_c->mutex), 0);

    //Initialize the state of the connection, default to 0 due to memset.
    new_tcp_c->tcp_inf.tcpi_state = TCP_SYN_SENT;
    new_tcp_c->tcp_inf.tcpi_snd_wscale = 0x1;
    new_tcp_c->tcp_inf.tcpi_ato = htons(ACK_TIMEOUT);
    new_tcp_c->tcp_inf.tcpi_snd_mss = htons(UTCP_MSS); //mss which we will send
    new_tcp_c->tcp_inf.tcpi_rto = htons(RTO);
    new_tcp_c->tcp_inf.tcpi_rtt = htons(RTT);

    //New packet initialization
    new_packet = malloc(sizeof (*new_packet));
    memset(new_packet, 0, sizeof (*new_packet));

    //FIXME->HEM DE MIRAR COM GESTIONEM LES OPTIONS.
//    init_options(new_packet->options, new_tcp_c->tcp_inf);

    //Connection basics
    //destination is the remote IP address
    //source is our listening ip address
    //Packet:
    //Header
    new_packet->header.source = htons(src_port); /* source port (ours) */
    new_packet->header.dest = htons(dst_port); /* destinat. port (remote)*/
    new_packet->header.seq = 0;
    //Flags
    new_packet->header.syn = 0x1;
    //Control
    new_packet->header.window = htonl(recv_buffer.left_size);
    new_packet->payload_size = 0;
    new_packet->header.doff = 5; //5 words of 32 bits, tcphdr length
    new_packet->header.check = tcp_checksum(new_packet);

    struct timespec t0, t1;
    clock_gettime(CLOCK_MONOTONIC, &t0);
    clock_gettime(CLOCK_REALTIME, &t1);
    t1.tv_sec += RTO;

    //Enviem el syn+ack
    tcp_ip_send(new_tcp_c, new_packet);

    (new_tcp_c->tcp_inf).tcpi_state = TCP_SYN_SENT;
    (new_tcp_c->tcp_inf).tcpi_last_ack_sent = htonl((u_int32_t) t0.tv_nsec); //ns, usec, sec?

    //Podriem fer-ho abans d'enviar el paquet, i si no rebem el paquet
    //eliminar la connexió de la llista
    pthread_mutex_lock(&connection_list_mutex);
    list_add_tail(&(new_tcp_c->element), &connection_list);
    pthread_mutex_unlock(&connection_list_mutex);

    debug_printf("TCP", "(TCP): Created new TCP connection\n");

    //ACK SENT.. we must wait for an "ACK OF SYNC" reply to be ESTABLISHED for a max of 3 seconds..
    sem_timedwait(&(new_tcp_c->sem), &t1);
    if (errno == ETIMEDOUT && list_empty(&(new_tcp_c->packet_queue))) {
        pthread_mutex_lock(&connection_list_mutex);
        list_del(&(new_tcp_c->element));
        pthread_mutex_unlock(&connection_list_mutex);
        free(new_tcp_c); //Hem d'entrar dins la cua de paquets pendents i fer free

        debug_printf("TCP", "(TCP): Connection timeout\n");
        return NULL;
    } else {
        pthread_mutex_lock(&new_tcp_c->mutex);
        if (list_empty(&(new_tcp_c->packet_queue))) {
            debug_printf("TCP", "(TCP): Undefined error on accept()\n");
            return NULL;
        } else {
            struct unet_tcp_packet *packet;
            packet = list_head_to_utcp_packet(list_first(&(new_tcp_c->packet_queue)));
            if (packet->header.ack == 0x1 && packet->header.syn == 0x1) {
                new_tcp_c->local_addr = packet->d_address;
                new_tcp_c->tcp_inf.tcpi_state = TCP_ESTABLISHED;
                debug_printf("TCP", "(TCP): Connection established\n");
                //Falta enviar un ack! :: FIXME
            }
            list_del(list_first(&(new_tcp_c->packet_queue)));
        }
        pthread_mutex_unlock(&new_tcp_c->mutex);
    }

    return new_tcp_c;
}

int
unet_tcp_listen_close(struct unet_tcp_listen_node * listen_node) {
    struct list_head * pos;
    struct unet_tcp_packet * pak;

    debug_printf("TCP", "(TCP): Closing listen node\n");

    pthread_mutex_lock(&listen_list_mutex);
    list_del(&(listen_node->element));
    pthread_mutex_unlock(&listen_list_mutex);

    while (!list_empty(&listen_node->syn_rcvd_q)) {
        pos = list_first(&listen_node->syn_rcvd_q);
        pak = list_head_to_utcp_packet(pos);
        list_del(&(pak->element));
        free(pak);
    }

    free(listen_node);
    debug_printf("TCP", "(TCP): Node closed\n");
    return 0;
}

int
unet_tcp_conn_close(unet_tcp_connection_t connection) {
    //Tanca una connexió
    debug_printf("TCP", "(TCP): Closing connection\n");
    return 0;
}

void
unet_tcp_send(unet_tcp_connection_t conn, const void *buf, size_t n) {
    //L'aplicació ens diu que enviem el que hem d'enviar.
    //Hem d'enviar un paquet *buf de mida n, amb la fragmentació, etc.
    //Dins state, hi haurà les adreçes IPs, port origen, port destí...
    //Llavors servidorUnet::sent_ip_packet(ldlsafdl);

    debug_printf("TCP", "(TCP): sending data via TCP: conn_id: %p , buf_id: %p , buf_sz: %lu \n", conn, buf, (unsigned long) n);
}

size_t
unet_tcp_recv(unet_tcp_connection_t conn, void * buf, size_t n) {
    // Petició de l'aplicacio per llegir dades (read)
    // Haurà de passar n bytes de dades llegits de conn
    // a l'aplicació.
    // (Fragmentació).
  struct unet_tcp_packet * p;
  struct list_head * lh;
  size_t read_data_sz, wr_step;

  read_data_sz = 0;

  debug_printf("TCP", "(TCP): App. request for %i bytes of data\n",n);

  while (read_data_sz < n)
    {
      sem_wait(&conn->sem);
      pthread_mutex_lock(&conn->mutex);
      lh = list_first(&conn->packet_queue);
      p = list_head_to_utcp_packet(lh);
      list_del(lh);      
      pthread_mutex_unlock(&conn->mutex);

      recv_buffer.left_size += p->payload_size;
      printf("Decapsulating!: %p paysize: %i \n",p,(uint32_t) p->payload_size);
      if (p->header.doff*4 != 20)   //These packet has options
	  p->payload += p->header.doff*4 - 20;

      wr_step = p->payload_size;
      if (n - read_data_sz < p->payload_size) wr_step = n-read_data_sz;	  
      memcpy(buf,p->payload,wr_step);
      read_data_sz += wr_step;
      if (p->header.psh == 0x01) return read_data_sz;
      //      free_packet(p);
    }
    debug_printf("TCP", "(TCP): sending data to application\n");
    return read_data_sz;
}

void
unet_tcp_deliver(struct in_addr s_addr, struct in_addr d_addr, void * buf, size_t n) {
    /*
     * Aquesta funció reb un paquet de IP i el col·loca convenientment a la llista que
     * faixi falta.
     * Si el paquet és per nosaltres i té el flag syn activat, s'envia a la syn_recv_q de un listen_node.
     * Si no té el flag syn activat, es cerca la connexió associada al paquet i si es troba
     * i està en estat de rebre paquets, l'insereix a la cua packet_queue.
     * Utilitza els semàfors de les cues per impedir l'accés concurrent d'altres funcións.
     * s_addr = remote host address
     * d_addr = our host address
     * buf = payload of the tcp packet
     * n = size of the payload
     */

    struct tcphdr * header;
    struct unet_tcp_packet * tcp_p;

    debug_printf("TCP", "(TCP): Packet received from outside!: %i bytes\n",(uint32_t) n);
    
    if (recv_buffer.left_size < n)
        debug_printf("TCP", "(TCP): Packet discarded due to rcv_buffer full\n");
    else
    {
        header = (struct tcphdr *) buf;
        tcp_p = malloc(sizeof (*tcp_p));        

        //data offset is expressed in bytes/4
        tcp_p->payload_size = n - header->doff * 4;
        tcp_p->opt.len = header->doff * 4 - 20;

        if (tcp_p->opt.len != 0)
        {    //These packet has options
            tcp_p->opt.options = malloc (tcp_p->opt.len);
            memcpy(&tcp_p->header + 20,tcp_p->opt.options,tcp_p->opt.len);
        }

        if (tcp_p->payload_size != 0) {
            //These packet has data
            tcp_p->payload = malloc((size_t) tcp_p->payload_size);
            memcpy(tcp_p->payload, header + (header->doff * 4), tcp_p->payload_size);
        }

        memcpy(&(tcp_p->header), header, sizeof (struct tcphdr));
        tcp_p->s_address.s_addr = s_addr.s_addr;
        tcp_p->d_address.s_addr = d_addr.s_addr;

        //Manage the packet and insert in the right queue
        receive_manager(tcp_p,n);
    }
}

unet_tcp_connection_t
unet_tcp_accept(struct unet_tcp_listen_node *listen_node) {
    /*Descripció:
       Aquesta funció es crida quan es rep una petició d'accept per part
       d'un servidor.

       Cerca el node de la listen_list amb <port,ip>, el treu de la cua
       i comença el protocol 3-Way-Handshaking.

       Si no té cap node a la cua, bloca fins que n'arriba un.

       Crea una connexió i la retorna.
     */


    //Status is LISTEN
    struct unet_tcp_packet * syn_packet, * new_packet;
    struct list_head *curr;
    unet_tcp_connection_t new_tcp_c;

    printf("(TCP): Waiting for somebody in accept(), Listen Addr: %s, Port: %u, Available conn. req. slots: %i\n"
            , inet_ntoa(listen_node->listen_addr), ntohs(listen_node->port), listen_node->pending_syn_slots);


    //Waiting to get a syn packet...
    if (sem_wait(&listen_node->sem) == -1) {
        debug_printf("TCP", "(TCP): Error on accept() semaphore\n");
        return NULL;
    }

    //Now we received a syn packet, so status is SYN_RCVD, let's start 3-way-h
    pthread_mutex_lock(&(listen_node->mutex));
    curr = list_first(&(listen_node->syn_rcvd_q));
    listen_node->pending_syn_slots++;
    list_del(curr);
    pthread_mutex_unlock(&(listen_node->mutex));

    //Quant tenim el syn_packet, el convertirem a un unet_tcp_packet
    syn_packet = list_head_to_utcp_packet(curr);

    //Create a new connection
    new_tcp_c = malloc(sizeof (*new_tcp_c));
    memset(new_tcp_c, 0, sizeof (*new_tcp_c));

    //New connection initialization
    new_tcp_c->local_addr = listen_node->listen_addr;
    new_tcp_c->remote_addr = syn_packet->s_address;
    new_tcp_c->local_port = listen_node->port;
    new_tcp_c->remote_port = syn_packet->header.source;
    INIT_LIST_HEAD(&(new_tcp_c->packet_queue));
    sem_init(&(new_tcp_c->sem), 1, -1);
    pthread_mutex_init(&(new_tcp_c->mutex), 0);

    //Initialize the state of the connection, default to 0 due to memset.
    new_tcp_c->tcp_inf.tcpi_state = TCP_SYN_RECV;
    new_tcp_c->tcp_inf.tcpi_probes = PROBES;
    new_tcp_c->tcp_inf.tcpi_backoff = BACKOFF;


    if (syn_packet->opt.len != 0)
    {
      set_conn_options(&syn_packet->opt, &new_tcp_c->tcp_inf);
    }
    new_tcp_c->tcp_inf.tcpi_snd_wscale = SND_WSCALE; /**Only used if tcp_inf.options set properly**/
    new_tcp_c->tcp_inf.tcpi_rto = RTO;
    new_tcp_c->tcp_inf.tcpi_ato = ACK_TIMEOUT;
    new_tcp_c->tcp_inf.tcpi_snd_mss = UTCP_MSS; /**Only used if tcp_inf.options set properly**/
    new_tcp_c->tcp_inf.tcpi_pmtu = UIP_MTU;
    new_tcp_c->tcp_inf.tcpi_snd_ssthresh = 0;

    if (new_tcp_c->tcp_inf.tcpi_options & TCPI_OPT_WSCALE)
        new_tcp_c->tcp_inf.tcpi_snd_cwnd = new_tcp_c->tcp_inf.tcpi_advmss * new_tcp_c->tcp_inf.tcpi_rcv_wscale;
    else
        new_tcp_c->tcp_inf.tcpi_snd_cwnd = new_tcp_c->tcp_inf.tcpi_advmss;
    
    new_tcp_c->tcp_inf.tcpi_advmss = ntohs(syn_packet->header.window);
    new_tcp_c->tcp_inf.tcpi_rtt = RTT;

    debug_printf("TCP", "(TCP): Created new TCP connection\n");

    //New packet initialization
    new_packet = malloc(sizeof (*new_packet));
    memset(new_packet, 0, sizeof (*new_packet));

    //Connection basics
    //destination is the remote IP address
    //source is our listening ip address
    //Packet:
    //Header
    new_packet->header.source = listen_node->port; /* source port (ours). It's syn_packet->header.dest*/
    new_packet->header.dest = syn_packet->header.source; /* destinat. port (remote)*/
    new_packet->header.seq = 0; /*Random seq. number*/
    new_packet->header.ack_seq = htonl(ntohl(syn_packet->header.seq) + 1);
    //Flags
    new_packet->header.syn = 0x1;
    new_packet->header.ack = 0x1;
    //Control
    new_packet->header.window = htons(recv_buffer.left_size);
    new_packet->s_address = new_tcp_c->local_addr;
    new_packet->d_address = new_tcp_c->remote_addr;
    new_packet->header.doff = 5; //5 words of 32 bits, tcphdr length
    new_packet->header.check = tcp_checksum(new_packet); //Actually managed for Unet server...

    struct timespec timeout,now;
    clock_gettime(CLOCK_REALTIME, &now);
    clock_gettime(CLOCK_REALTIME, &timeout);
    timeout.tv_sec += new_tcp_c->tcp_inf.tcpi_ato;

    //Enviem el syn+ack
    tcp_ip_send(new_tcp_c, new_packet);
    new_tcp_c->tcp_inf.tcpi_last_ack_sent = (u_int32_t) now.tv_nsec; //ns, usec, sec?

    pthread_mutex_lock(&connection_list_mutex);
    list_add_tail(&(new_tcp_c->element), &connection_list);
    pthread_mutex_unlock(&connection_list_mutex);

    //Ack sent.. we must wait for a remote ack to be ESTABLISHED
    sem_timedwait(&(new_tcp_c->sem), &timeout);

    if (errno == ETIMEDOUT && list_empty(&(new_tcp_c->packet_queue)))
    {
        free_connection(new_tcp_c);
        debug_printf("TCP", "(TCP): Connection timeout\n");
        return NULL;
    }
    else
    {
        pthread_mutex_lock(&new_tcp_c->mutex);
        if (list_empty(&(new_tcp_c->packet_queue)))
        {
            debug_printf("TCP", "(TCP): Undefined error on accept()\n");
            return NULL;
        } 
        else
        {
            struct unet_tcp_packet *packet;
            clock_gettime(CLOCK_REALTIME, &now);
            new_tcp_c->tcp_inf.tcpi_rtt =  (u_int32_t) now.tv_nsec - new_tcp_c->tcp_inf.tcpi_last_ack_sent;
            packet = list_head_to_utcp_packet(list_first(&(new_tcp_c->packet_queue)));
            if (packet->header.ack == 0x1) {
                new_tcp_c->tcp_inf.tcpi_state = TCP_ESTABLISHED;
                debug_printf("TCP", "(TCP): Connection established. Rtt: %u (State: TCP_ESTABLISHED)\n",new_tcp_c->tcp_inf.tcpi_rtt);
            }
            list_del(list_first(&(new_tcp_c->packet_queue)));
            free_packet(packet);
        }
        pthread_mutex_unlock(&new_tcp_c->mutex);
    }
    return new_tcp_c;
}


void set_conn_options(struct tcp_options * o, struct tcp_info * c_status)
{
    c_status->tcpi_options = 0;
    //parse_options, the following values must be extracted from *o
    c_status->tcpi_options |= TCPI_OPT_WSCALE;
    c_status->tcpi_rcv_wscale = 0x3;
    c_status->tcpi_rcv_mss = 0;
}

u_int32_t get_tcp_time() {
    //Get the current Time in ms
    return 450;
}

u_int16_t tcp_checksum(struct unet_tcp_packet * packet) {
    return 0;
}

void free_connection(unet_tcp_connection_t conn)
{
    pthread_mutex_lock(&connection_list_mutex);
    list_del(&conn->element);
    pthread_mutex_unlock(&connection_list_mutex);

    pthread_mutex_lock(&conn->mutex);
    while (!list_empty(&conn->packet_queue))
    {
        struct list_head * l;
        l = list_first(&(conn->packet_queue));
        list_del(l);
        free_packet(list_head_to_utcp_packet(l));
    }
    pthread_mutex_unlock(&conn->mutex);
    free(conn);
}

void free_packet(struct unet_tcp_packet * p)
{
    if (p->payload_size != 0)
        free(p->payload);
    if (p->opt.len != 0)
        free(p->opt.options);
    free(p);
}

void
tcp_ip_send(unet_tcp_connection_t conn, struct unet_tcp_packet * packet) {

    void * buffer;

    //Take options in mind..
    size_t size_to_copy = sizeof (struct tcphdr) + packet->payload_size;

    buffer = malloc(size_to_copy);

    memcpy(buffer, packet, sizeof (struct tcphdr));

    buffer += sizeof (struct tcphdr);

    memcpy(buffer, packet->payload, packet->payload_size);

    debug_printf("TCP", "(TCP): Sending to IP: dest: %s, src: %s, src_p: %u, dst_p: %u\n",
            inet_ntoa(packet->s_address), inet_ntoa(packet->d_address), ntohs(packet->header.source),
            ntohs(packet->header.dest));

    if (unet_transport_send_packet(UNET_TCP,
            conn->remote_addr,
            buffer - sizeof (struct tcphdr),
            size_to_copy) == -1)
        debug_printf("TCP", "(TCP): Error from IP when sending packet");

    free(packet);
}

void
receive_manager(struct unet_tcp_packet * tcp_p, size_t n)
{
    struct list_head * position;
    struct unet_tcp_listen_node * current_ln;
    unet_tcp_connection_t current_con;
    uint8_t found;
    found = 0;

    /*Wow, if we are here, we have a packet! Let's put it in the right queue, and update
      the state of the associated connection if proceeds.*/

    /*If packet is Syn (not Syn+Ack), we are the server. We must check if there are
      a listen_node for these packet, and if it exists, we will copy the packet to these listen_node.*/
    if (tcp_p->header.syn == 0x01 && tcp_p->header.ack == 0x00)
    {
        pthread_mutex_lock(&listen_list_mutex);
        list_for_each(position, &listen_list)
        {
            current_ln = list_head_to_listen_node(position);
            if (current_ln->port == tcp_p->header.dest
                    && current_ln->listen_addr.s_addr == tcp_p->d_address.s_addr) 
                {
                found = 1;
                pthread_mutex_lock(&current_ln->mutex);
                pthread_mutex_unlock(&listen_list_mutex);
                if (current_ln->pending_syn_slots == 0)
                {
                    debug_printf("TCP", "(TCP): Max connection req. reached\n");
                } 
                else
                {
                    current_ln->pending_syn_slots--;
                    list_add_tail(&tcp_p->element, &current_ln->syn_rcvd_q);
                    debug_printf("TCP", "(TCP): Received packet and inserted into his lnlist (State: LISTEN)\n");
                    sem_post(&current_ln->sem);
                    pthread_mutex_unlock(&current_ln->mutex);
                }
                break;
               }
        }
    if (!found) pthread_mutex_unlock(&listen_list_mutex);
    } 
    else
    {
        /* En aquest cas estem tractant amb una connexió establerta
	   el paquet s'ha d'inserir a la connexió pertinent*/
      //      recv_buffer.left_size -= n;
        pthread_mutex_lock(&connection_list_mutex);
        list_for_each(position, &connection_list)
        {
            current_con = (unet_tcp_connection_t) list_head_to_tcp_connection(position);
            if (current_con->local_addr.s_addr == tcp_p->d_address.s_addr
                    && current_con->local_port == tcp_p->header.dest
                    && current_con->remote_port == tcp_p->header.source)
            {
	      found = 1;

	      pthread_mutex_unlock(&connection_list_mutex);

	      /**************************************CONNECTION IS ALIVE!*********************************************/
	      /** We got the connection for these packet, let's check if it's in a state
		  capable to receive packets, if the received packet is data or ack,
		  send his ack if it's data and update the tcp state **/ 			

	      /*3-Way-H*/
	      if (current_con->tcp_inf.tcpi_state == TCP_SYN_RECV)
		{
		  /*We are a server that has received a SYN, and we are in accept(), so we must:
		    1. Move the packet to the connection packet queue
		    2. Send a signal to the connection to say that she has a packet so accept() continues
		    Comment: In these case, all the acks and other stuff are managed by accept()*/		    
		  list_add_tail(&tcp_p->element, &current_con->packet_queue);
		  sem_post(&current_con->sem);		  
                  debug_printf("TCP", "(TCP):  Received packet and inserted into his conn (State: TCP_SYN_RECV)\n");
		}
	      
	      if ((tcp_p->header.ack == 0x00 && current_con->tcp_inf.tcpi_state != TCP_CLOSE)||
		  (tcp_p->header.ack == 0x01 && tcp_p->header.psh == 0x01))		
		{
		  /*Received DATA PACKET.
		    We are the receptor, and we are able to receive packets:
		    1. Check the status of the connection, and send the corresponding ack to the sender
		    2. Send a signal to the connection to say that she has a new packet */		    
		  struct unet_tcp_packet * ack_packet = malloc(sizeof (*ack_packet));
		  memset(ack_packet, 0, sizeof (*ack_packet));
		  //update_con_options(ack_packet->options, current_con->tcp_inf);
		  
		  ack_packet->header.source = current_con->local_port; /* source port (ours). It's syn_packet->header.dest*/
		  ack_packet->header.dest = current_con->remote_port; /* destinat. port (remote)*/
		  ack_packet->header.seq =  ntohl(tcp_p->header.ack); /* Next data we want */
//HEM DE TENIR EN COMPTE LEN, PERO LEN ES INCORRECTE!!!!!!
		  ack_packet->header.ack_seq = htonl(ntohl(tcp_p->header.seq)+5); /* Next data we want */ 	     
		  
		  //Flags
		  ack_packet->header.ack = 0x1;
		  //Control
		  ack_packet->header.window = htons(recv_buffer.left_size);
		  ack_packet->payload_size = 0;
		  ack_packet->s_address = current_con->local_addr;
		  ack_packet->d_address = current_con->remote_addr;
		  ack_packet->header.doff = 5; //5 words of 32 bits, tcphdr length
		  ack_packet->header.check = tcp_checksum(ack_packet);
          	  struct timespec timeout,now;
                  clock_gettime(CLOCK_REALTIME, &now);
                  clock_gettime(CLOCK_REALTIME, &timeout);
                  timeout.tv_sec += current_con->tcp_inf.tcpi_ato;
		  
                  //Enviem l'ACK, activem una alarma de retransmissió d'ack?
                  tcp_ip_send(current_con, ack_packet);
                  current_con->tcp_inf.tcpi_last_ack_sent = (u_int32_t) now.tv_nsec; //ns, usec, sec?
		  sem_post(&current_con->sem);
                  debug_printf("TCP", "(TCP):  Received packet %p and inserted into his conn  (State: ESTABLISHED)\n",tcp_p);
		}
	      /** End of ack send **/	      	     


	      /**************************************************************************************************/
	      break;
            }        
	}
	if (!found)
	  {
	    pthread_mutex_unlock(&connection_list_mutex);
	    recv_buffer.left_size += n;
	  }
    }
    
    if (!found)
      {
        //Discarding packet, not for us.
        //Must send connection refused if this happens through ICMP. Not Implemented.
        debug_printf("TCP", "(TCP):  Discarding packet from tcp packet manager\n");
        debug_printf("TCP", "(TCP): syn: %u\n", tcp_p->header.syn);
        debug_printf("TCP", "(TCP): src: %u, dest: %u\n", ntohs(tcp_p->header.source), ntohs(tcp_p->header.dest));
        debug_printf("TCP", "(TCP): rm_addr: %s, loc_addr: %s\n", inet_ntoa(tcp_p->s_address), inet_ntoa(tcp_p->d_address));
	free(tcp_p);
      }
}

/*
 * Funcions de llistes enllaçades a estructures de dades
 */
struct unet_tcp_listen_node *
list_head_to_listen_node(struct list_head *l) {
    return list_entry(l, struct unet_tcp_listen_node, element);
}

struct unet_tcp_packet *
list_head_to_utcp_packet(struct list_head *l) {
    return list_entry(l, struct unet_tcp_packet, element);
}

unet_tcp_connection_t *
list_head_to_tcp_connection(struct list_head *l) {
    unet_tcp_connection_t dummy = (unet_tcp_connection_t) 0;

    struct list_head *lh = &(dummy->element);

    return (unet_tcp_connection_t *) (((char *) (l) - (unsigned long) lh));
}

